#include <stdint.h>
#include "error_code.h"
#include "base.h"
#include "character_module.h"
#include "etu_timer.h"
#include "card_param.h"
#include "Calculate.h"
#include "slot.h"

#include "Log.h"


#undef is_TD_present
//#define is_TCK_correct(atr, atr_len) (Buffer_Xor(atr, atr_len) == 0)
#define is_TCK_present(TD) (((TD) & 0x0F) != 0)
#define is_TD_present(TD) (((TD) & 0x80) != 0)

static uint8_t get_high_nibble_setbit_number(uint8_t data)
{
    const static uint8_t set_bit_num[] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4};
    return set_bit_num[data >> 4];
}

static uint32_t is_TCK_correct(uint8_t atr[], uint8_t atr_len)
{
    return Buffer_Xor(atr + 1, atr_len - 1) == 0;
}

static uint8_t get_lenght_to_receive_from_TD(uint8_t TD)
{
    return get_high_nibble_setbit_number(TD);
}

static uint8_t get_char_parity_bit(uint16_t ch)
{
    return (ch >> 8) & 1u;
}

static uint32_t is_even_number(uint8_t number)
{
    return (number & 1u) == 0u;
}

static uint32_t check_char_even_parity(uint16_t ch)
{
    uint8_t data;
    uint8_t bit_amount;
    uint8_t parity_bit;

    data = ch;
    bit_amount = get_high_nibble_setbit_number(data) +  get_high_nibble_setbit_number(data << 4);
    parity_bit = get_char_parity_bit(ch);
    bit_amount += parity_bit;

    return is_even_number(bit_amount);
}

static uint32_t check_char_odd_parity(uint16_t ch)
{
    return !check_char_even_parity(ch);
}

static uint32_t check_atr_char_parity(character_module_t *module, uint16_t ch)
{
    if(module->byte_direction == DIRECT_BYTE)
    {
        return check_char_even_parity(ch);
    }
    else
    {
        return check_char_odd_parity(ch);
    }
}

static uint16_t atr_convert_reverse_byte(uint16_t ch){
	uint16_t c = ~ch;
	uint16_t parity_bit;
	
	c &= 0x01FF;
	parity_bit = c & 0x0100;
	c = reverse_byte(c);
	return c | parity_bit;
}

static uint32_t receive_atr_byte(character_module_t *module, uint8_t *byte, uint32_t etu)
{
    uint32_t ret = NO_ERR;
    uint16_t data = 0;
    uint32_t clk = ETUTimer_ETU2Clock(etu, module->FiDi);

    ret = HardwareModule_ReceiveByte(module->hw, &data, clk);
    CharacterModule_TimerReset(module);

    if((ret == ERR_TIMEOUT) || (ret == ERR_CARD_ABSENT)){

        return ret;
    }




	if(module->byte_direction == REVERSE_BYTE){
		data = atr_convert_reverse_byte(data);
	}
	


    if(!check_char_even_parity(data)){
        ret = ERR_PARITY;
    }
    else{

		ret = NO_ERR;
    }
    

    *byte = (uint8_t)data;
    return ret;
}

static uint32_t receive_atr_block(character_module_t * module, uint8_t block[], uint8_t block_len, uint32_t etu)
{
    uint8_t i;
    uint32_t ret = NO_ERR;
    for(i = 0; i < block_len; i++)
    {
        ret = receive_atr_byte(module, block + i, etu);

        if(ret != NO_ERR)
        {
            break;
        }
    }

    return ret;
}


static uint32_t receive_TS(character_module_t * module, uint8_t *ts, uint32_t wait_time)
{
    uint32_t ret;
    
    CharacterModule_TimerStart(module, wait_time);
    ret = receive_atr_byte(module, ts, wait_time);
    CharacterModule_TimerStop(module);

    if(ret == ERR_PARITY)
    {
        if(*ts == 0x03)
        {
			module->byte_direction = REVERSE_BYTE;
            *ts = 0x3F;
            ret = NO_ERR;
        }

        /*
        	return parity error
        */
    }
    else if((ret == NO_ERR))
    {
        if(*ts != 0x3B)
        {
            ret = ERR_TS;
        }
    }

    return ret;
}

static uint32_t receive_T0(character_module_t * module, uint8_t *t0, uint32_t etu)
{
    return receive_atr_byte(module, t0, etu);
}

static uint32_t receive_TCK(character_module_t * module, uint8_t *tck, uint32_t etu)
{
    return receive_atr_byte(module, tck, etu);
}

static uint32_t receive_history(character_module_t * module, uint8_t history[], uint8_t history_len, uint32_t etu)
{
    return receive_atr_block(module, history, history_len, etu);
}

static uint32_t receive_ATR(slot_t *slot, uint8_t atr[], uint8_t *atr_len)
{
    uint32_t ret = NO_ERR;
    uint8_t rx_len = 0;
    uint8_t history_len;
    uint8_t TCK_len = 0;
    uint8_t TD;
    uint8_t T0;
    uint8_t len_to_receive;
    icc_t *icc = slot->icc;
    character_module_t * module = slot->module;
    uint8_t FiDi;
	uint32_t WWT = icc->WWT;

    FiDi = icc->FiDi;
    /*
    The terminal shall have a reception window which is opened no later than
    380 clock cycles after time T1 and closed no earlier than 42,000 clock cycles
    after time T1.
    42000clock + 12etu = waittime, because we check the end of the char.
    */
    ret = receive_TS(module, atr, (42000 / 372 + 1) * 4 + icc->char_duration);

    if(ret != NO_ERR)
    {
        goto RECIEVE_OUT;
    }

    /*
    The terminal shall be able to receive an ATR having a duration of less than or
    equal to 20,160 initial etus.
    */
//	    ETUTimer_StartAlarmer(20160, FiDi);
//		uint32_t c1 = ETUTimer_GetCountor();
    CharacterModule_TimerStart(slot->module, icc->WWT);
    ++rx_len;

    ret = receive_T0(module, atr + rx_len, WWT);

    if(ret != NO_ERR)
    {
        goto RECIEVE_OUT;
    }

    T0 = atr[rx_len];
    ++rx_len;
    history_len = T0 & 0x0F;
    TD = T0 & 0xF0;

    while((len_to_receive = get_lenght_to_receive_from_TD(TD)) != 0)
    {
        ret = receive_atr_block(module, atr + rx_len, len_to_receive, WWT);

        if(ret != NO_ERR)
        {
            goto RECIEVE_OUT;
        }

        rx_len += len_to_receive;


        if(is_TD_present(TD))
        {
            TD = atr[rx_len - 1];

            if(is_TCK_present(TD))
            {
                TCK_len = 1;
            }
        }
        else
        {
            break;
        }

    }

    ret = receive_history(module, atr + rx_len, history_len, WWT);

    if(ret != NO_ERR)
    {
        goto RECIEVE_OUT;
    }

    rx_len += history_len;

    if(TCK_len != 0)
    {
        ret = receive_TCK(module, atr + rx_len, WWT);

        if((ret != NO_ERR))
        {
            goto RECIEVE_OUT;
        }

        ++rx_len;

        /*
        The value of TCK is such that the exclusive-OR ing of all bytes from T0
        to TCK inclusive is null
        */
        if(!is_TCK_correct(atr, rx_len))
        {
            ret = ERR_TCK;
            goto RECIEVE_OUT;
        }
    }

    *atr_len = rx_len;

RECIEVE_OUT:

//	    CharacterModule_TimerStop(slot->module);
//	    ETUTimer_StopAlarmer();
    return ret;
}

static uint8_t get_tck_len(card_param_t *param)
{
    uint8_t i;
    uint8_t tck_len = 0;
    uint32_t TD;

    for(i = 1; i < 9; i++)
    {
        TD = card_param_get_specific_char(param, C_TD, i);

        if(TD > 0xFF)
        {
            break;
        }

        if(is_TCK_present(TD))
        {
            tck_len = 1;
            break;
        }
    }

    return tck_len;
}


static uint8_t get_atr_history_len(uint8_t atr[])
{
    return atr[1] & 0x0F;
}

static uint32_t check_atr(uint8_t atr[], uint8_t atr_len, card_param_t *param)
{
    uint8_t expect_atr_len;
    uint8_t tck_len;

    if((atr_len > 32) || (atr_len < 2))
    {
        return ERR_ATR_LEN;
    }

    expect_atr_len = card_param_init(param, atr);
    expect_atr_len += get_atr_history_len(atr);
    tck_len = get_tck_len(param);
    expect_atr_len += tck_len;

    if(expect_atr_len > atr_len)
    {
        return ERR_ATR_INCOMPELET;
    }

    if(expect_atr_len < atr_len)
    {
        return ERR_REJECT_ATR;
    }

    if(tck_len > 0 && !is_TCK_correct(atr, atr_len))
    {
        return ERR_TCK;
    }

    return NO_ERR;
}


#define COLD_RESET_MODE		1
#define WARM_RESET_MODE	2

#define LS_Nibble(ch) ((uint8_t)((ch) & 0x0F))
#define MS_Nibble(ch) ((uint8_t)(ch) >> 4)

static uint32_t is_TA2_valid(uint8_t TD1, uint8_t TA2)
{
    /*
    	 The terminal shall accept an ATR containing TA2 provided
    	that all the following conditions are met:
    	?  The protocol indicated in the l.s. nibble is also the first indicated protocol in
    	the ATR.
    	?  b5 = 0
    	?  The terminal is able to support the exact conditions indicated in the
    	applicable interface characters and immediately uses those conditions.
    	Otherwise, the terminal shall reject an ATR containing TA2.

    	*/

    if((TA2 & 0x0F) != (TD1 & 0x0F))
    {
        return 0;
    }

    if((TA2 & (1 << 4)) != 0)
    {
        return 0;
    }

    return 1;
}

static uint32_t is_TA1_support(uint8_t TA1)
{
    //return 0x11 <= TA1 && TA1 <= 0x13;
    return TA1 != 0u;
}

static uint32_t is_TA1_valid(uint8_t TA1)
{
    //非法的FI,DI转换后，返回值为0
    return convert_fi_code_to_value(TA1 >> 4)
           && convert_di_code_to_value(TA1 & 0x0F)
           && is_TA1_support(TA1);
}

static uint8_t PPS_Request(slot_t *slot, uint8_t req[], uint8_t len)
{
	uint32_t extra_guardtime = slot->icc->extra_guardtime;
	LOG_SBUF("PPS tx", req, len);
    return CharacterModule_SendData(slot->module, req, len, extra_guardtime);
}

static uint8_t PPS_Response(slot_t *slot, uint8_t resp[], uint8_t len)
{
    uint8_t ret = CharacterModule_ReceiveData(slot->module, resp, len, slot->icc->WWT);
	LOG_SBUF("PPS rx", resp, len);
	return ret;
}

static uint8_t PPS(slot_t *slot, uint8_t ta1, uint8_t protocol_type, uint8_t *fidi)
{
    uint8_t error;
    uint8_t req[6];
    uint32_t req_len = 4;

    req[0] = 0xFF;

    if(protocol_type != 0)
    {
        req[1] = 0x11;
    }
    else
    {
        req[1] = 0x10;
    }

    req[2] = ta1;
    req[3] = Buffer_Xor(req, 3);

    error = PPS_Request(slot, req, req_len);

    if(error != NO_ERR)
    {
        return error;
    }

    error = PPS_Response(slot, req, req_len);

    if(error != NO_ERR)
    {
        return error;
    }

    *fidi = req[2];
    return error;
}

static uint32_t decode_atr(slot_t *slot, 	uint8_t atr[], uint8_t atr_len, uint8_t mode)
{
    uint32_t ch;
    icc_t *icc = slot->icc;
    uint8_t TS;
    uint8_t T0;
    uint32_t TD1;
    uint32_t TA1;
    uint32_t TA2;
    uint32_t F, D;
    uint8_t FiDi;
    uint32_t TC1;
    uint32_t ret;
    card_param_t param;

    ret = check_atr(atr, atr_len, &param);

    if(ret != NO_ERR)
    {
        return ret;
    }

    //TS
    TS = atr[0];

    if(TS == 0x3B)
    {
        icc->byte_direction = DIRECT_BYTE;
    }
    else if(TS == 0x3F)
    {
        icc->byte_direction = REVERSE_BYTE;
    }
    else
    {
        return ERR_TS;
    }

    //T0
    T0 = atr[1];

    if(get_high_nibble_setbit_number(T0) == 0)
    {
        return NO_ERR;
    }

    TA1 = card_param_get_specific_char(&param, C_TA, 1);
    TD1 = card_param_get_specific_char(&param, C_TD, 1);
    TA2 = card_param_get_specific_char(&param, C_TA, 2);



    /*
    In response to a cold reset, the terminal shall accept only
    an ATR containing TB1 = '00'. In response  to a warm reset the terminal shall
    accept an ATR containing TB1 of any value (provided that b6 of T0 is set to 1) or
    not containing TB1 (provided that b6 of T0 is set to 0) and shall continue the card
    session as though TB1 = '00' had been returned.
    */
#if 0

    //TB1
    if(icc->work_mode != 0)
    {
        if(mode == COLD_RESET_MODE)
        {
            ch = card_param_get_specific_char(&param, C_TB, 1);

            if(ch != 0x00)
            {
                return ERR_REJECT_ATR;
            }
        }
    }

#endif
    //TC1

    ch = card_param_get_specific_char(&param, C_TC, 1);
    TC1 = ch;

    if(ch < 0xFF)
    {
        /*
        If the value of TC1 is in the range '00'  to 'FE', between 0 and 254 etus of extra
        guardtime shall be added to the minimum  character to character duration, which
        for subsequent transmissions shall be between 12 and 266 etus.
        */
        icc->extra_guardtime += ch;
    }
    else if(ch == 0xFF)
    {
        /*
        If the value of TC1 = 'FF', then the minimum character to character duration for
        subsequent transmissions shall be 12 etus if T=0 is to be used, or 11 etus if T=1 is
        to be used.
        */
        if(TD1 > 0xFF)
        {
            //use protocol T == 0

            return NO_ERR;
        }

        if((TD1 & 0x0F) == 0)
        {
            // protocol T == 0

        }
        else
        {
            // protocol T == 1
            icc->char_duration = 11;
        }
    }
    else
    {

        /*
        The terminal shall accept an ATR not containing TC1
        (provided that b7 of T0 is set to 0), and shall continue the card session as though
        TC1 = '00' had been returned.
        */
        TC1 = 0x00;
    }
    
    /*
    Accept the ATR if the value of TA1 is in the range '11' to '13',
    and immediately implement the values of F and D indicated.
    Reject the ATR if the value of TA1 is not in the range '11' to '13', unless it is
    able to support and immediately implement the conditions indicated.

    If TA1 is present in the ATR (indicated by b5 of T0 set to 1) and TA2 is not
    returned (negotiable mode), the terminal shall accept the ATR and shall continue
    using the default values of D = 1 and F = 372 during all subsequent exchanges,
    unless it supports a proprietary technique  for negotiating the parameters to be
    used.
    // we support all F and D
    */
    //TA1
    if(TA1 <= 0xFF) //TA1 present
    {
        if(!is_TA1_valid(TA1))
        {
            return ERR_REJECT_ATR;
        }

        if(TA2 > 0xFF)
        {
            //PPS ro Default FIDI
            if(TA1 != 0x11)
            {
                if(TD1 > 0xFF) {
                    TD1 = 0x10;
                }
				
                ret = PPS(slot, TA1, 1, &FiDi);

//	                ret = PPS(slot, TA1, TD1 & 0x0F, &FiDi);

                if(ret == NO_ERR)
                {
                    icc->FiDi = FiDi;
                }
                else
                {
                    return ret;
                }
            }
        }
        else
        {
            if(is_TA2_valid(TD1, TA2))
            {
                icc->FiDi = TA1;
            }
            else
            {
                return ERR_REJECT_ATR;
            }
        }
    }
    else
    {
      //icc->FiDi = 0x11;
    }

    F = convert_fi_code_to_value(icc->FiDi >> 4);
    D = convert_di_code_to_value(icc->FiDi & 0x0F);

    /*
    The terminal shall accept an ATR containing TD1 with the
    m.s. nibble having any value (provided that the value returned correctly
    indicates and is consistent with the in terface characters TA2 to TD2 actually
    returned),
    */
    //TD1
    if(TD1 > 0xFF)
    {
        uint8_t WI = 10;
        uint32_t WWT;
        /*9.2.2.1
        The terminal shall be able to correctly interpret a character sent by the ICC with
        a maximum interval between the leading edge of the start bit of the character
        and the leading edge of the start bit of th e previous character sent either by the
        ICC or the terminal of {WWT + (D x 480)} etus.
        */
        WWT = 960 * D * WI;
        icc->WWT = WWT + D * 480;
        return NO_ERR;
    }
    else
    {
        /*
        the l.s. nibble having a value  of '0' or '1'. The terminal shall reject
        an ATR containing other values of TD1.
        */
        if((TD1 & 0x0F) < 2)
        {
        	icc->protocol_type = 1;
//	            icc->protocol_type = TD1 & 0x0F;
        }
        else
        {
            return ERR_REJECT_ATR;
        }

        if(get_high_nibble_setbit_number(TD1) == 0x00)
        {
            return NO_ERR;
        }
    }

    //TA2

    if(TA2 <= 0xFF)
    {
        if(!is_TA2_valid(TD1, TA2))
        {
            return ERR_REJECT_ATR;
        }
    }

#if 1

    //TB2
    if(icc->work_mode != 0)
    {
        ch = card_param_get_specific_char(&param, C_TB, 2);

        if(ch <= 0xFF)
        {
            /*The terminal shall reject an ATR containing TB2.*/
            return ERR_REJECT_ATR;
        }
    }

#endif
    /*
    The terminal shall:
    ?  reject an ATR containing TC2 = '00'
    ?  accept an ATR containing TC2 = '0A'
    ?  reject an ATR containing TC2 having any other value unless it is able to
    support it.
    */
    {
        //TC2
        uint8_t WI;
        uint32_t WWT;

        ch = card_param_get_specific_char(&param, C_TC, 2);

        if(ch <= 0xFF)
        {
            if(ch == 0x00)
            {
                /* reject an ATR containing TC2 = '00'*/
                return ERR_REJECT_ATR;
            }

            /*accept any other value*/
            WI = ch;
        }
        else
        {
            /*default value of WI = 10 */
            WI = 10;
        }

        WWT = 960 * D * WI;
        icc->WWT = WWT + D * 480;
    }
    //TD2
    /*
     The terminal shall accept an ATR containing TD2 with the
    m.s. nibble having any value (provided that the value returned correctly
    indicates and is consistent with the in terface characters TA3 to TD3 actually
    returned), and the l.s. nibble having a value of '1' (or 'E' if the l.s. nibble of TD1 is
    '0'). The terminal shall reject an ATR containing other values of TD2.

    */
    ch = card_param_get_specific_char(&param, C_TD, 2);

    if(ch <= 0xFF)
    {
        //Accept the l.s. nibble having a value of '1' (or 'E' if the l.s. nibble of TD1 is '0')
        if(((ch & 0x0F) == 1)
                || (((TD1 & 0x0F) == 0) && ((ch & 0x0F) == 0x0E)))
        {

        }
        else
        {
            if(icc->work_mode != 0)
            {
                return ERR_REJECT_ATR;
            }
            else
            if((ch & 0x0F) == 0x0F){	//"T = 15"
            	//Not parse T=15
				return NO_ERR;
            }
        }

        if(get_high_nibble_setbit_number(ch) == 0x00)
        {
            return NO_ERR;
        }
    }
    else
    {
        return NO_ERR;
    }

    {
        //TA3
        /*
         The terminal shall accept an ATR not containing TA3
        (provided that b5 of TD2 is set to 0), and	shall continue the card session using a
        value of '20' for TA3. The terminal shall reject an ATR containing TA3 having a
        value in the range '00' to	'0F' or a value of 'FF'.
        */
        ch = card_param_get_specific_char(&param, C_TA, 3);

        if(ch < 0xFF)//TA3 present
        {
            if(ch <= 0x0F)
            {
                //reject 0<= TA3 <= 0x0F
                return ERR_REJECT_ATR;
            }

            icc->IFSC = ch;
        }
        else if(ch == 0xFF)
        {
            //reject TA3 == 0xFF
            return ERR_REJECT_ATR;
        }
        else
        {
            //accept TA3 absent, using TA3=0x20
            icc->IFSC = 0x20;
        }
    }

    {
        //TB3
        /*
        The terminal shall reject an ATR not containing TB3, or
        containing a TB3 indicating BWI greater than 4 and/or CWI greater than 5, or
        having a value such that 2^CWI <= (N + 1). It shall accept an ATR containing a TB3
        having any other value. N is the extra guardtime indicated in TC1.
        */
        uint8_t CWI;
        uint8_t BWI;
        uint8_t CWT;
        uint32_t BWT;
        uint32_t N;

        ch = card_param_get_specific_char(&param, C_TB, 3);

        if(ch <= 0xFF)
        {
            CWI = LS_Nibble(ch);
            BWI = MS_Nibble(ch);

            /* reject an ATR containing a TB3 indicating BWI greater than 4 and/or CWI greater than 5*/
#if 0
            if((CWI > 5) || (BWI > 4))
            {
                return ERR_REJECT_ATR;
            }
#endif 

            if(TC1 == 0xFF)
            {
                /*
                When using T=1, if TC1='FF', the value of N shall be taken as -1.
                N+1 = 0
                */
                N = 0;
            }
            else
            {
                N = TC1 + 1;
            }

            /*
            reject an ATR containing a TB3 having a value such that 2^CWI <= (N + 1)
            */
            if((1 << CWI) <= N)
            {
                return ERR_REJECT_ATR;
            }

            //EMV 4.3 Book1 9.2.4.2.2
            CWT = (1 << CWI) + 11;
            icc->CWT = CWT + 4;

            if(D == 1)
            {
                BWT = (1 << BWI) * 960 + 11;
            }
            else
            {
                BWT = (1 << BWI) * 960 * 372 * D / F + 11;
            }

            icc->BWT =  BWT + D * 960;
        }
        else
        {
            if(icc->work_mode != 0)
            {
                /*reject an ATR not containing TB3*/
                return ERR_REJECT_ATR;
            }
        }
    }

    {
        //TC3
        /*
        The terminal shall accept an ATR containing TC3 = '00'. It
        shall reject an ATR containing TC3 having any other value.
        */
        ch = card_param_get_specific_char(&param, C_TC, 3);

        if(ch <= 0xFF)
        {
            if(ch != 0)
            {
                return ERR_REJECT_ATR;
            }
        }
    }

    return NO_ERR;
}


static uint32_t reset_icc(slot_t *slot, uint8_t mode)
{
    uint32_t ret = NO_ERR;

    if(mode == COLD_RESET_MODE)
    {
        icc_t *icc = slot->icc;
        ret = Slot_ColdReset(slot, icc->voltage);
        /*
        physical_deactive(0);
        delay_ms(15);
        CharacterModule_Flush(slot->module);
        physical_cold_reset(0, 5);
        */
    }
    else
    {
      Slot_WarmReset(slot);
      //physical_warm_reset(0);
    }

    return ret;
}


static uint8_t searchT15(card_param_t *param)
{
    uint8_t i;
    uint32_t TD;

    for(i = 0; i < 8; i++)
    {
        TD = card_param_get_specific_char(param, C_TD, i);

        if(TD > 0xFF)
        {
            break;
        }

        if((TD & 0x0F) == 0x0F)
        {
            return i + 1;
        }
    }

    return 0;
}

static uint8_t voltage_to_mark(uint8_t voltage)
{
    switch(voltage)
    {
        case 2:
        {
            return 1 << 2;
        }

        case 3:
        {
            return 1 << 1;
        }

        case 5:
        {
            return 1;
        }
    }

    return 0;
}

static uint8_t mark_to_voltage(uint8_t mark)
{

    if(mark & 1)
    {
        return 5;
    }

    if(mark & (1 << 1))
    {
        return 3;
    }

    if(mark & (1 << 2))
    {
        return 2;
    }

    return 0;
}


static uint8_t get_voltage_mark(uint8_t atr[])
{
    uint8_t index;
    uint32_t TA;
    card_param_t param;

    card_param_init(&param, atr);
    index = searchT15(&param);

    if(index != 0)
    {
        TA = card_param_get_specific_char(&param, C_TA, index);

        if(TA <= 0xFF)
        {
            return TA;
        }
    }

    return 0;
}

static uint8_t config_voltage(uint8_t atr[], uint8_t *voltage)
{
    uint8_t mark;
    uint8_t vol_mark;
    uint8_t vol;
    mark = get_voltage_mark(atr);

    if(mark == 0)
    {
        return 0;
    }

    vol_mark = voltage_to_mark(*voltage);

    if(vol_mark == 0)
    {
        return 0;
    }

    if(vol_mark & mark)
    {
        return 0;
    }

    vol = mark_to_voltage(mark);

    if(vol == 0)
    {
        return vol;
    }

    *voltage = vol;
    return 1;
}

uint32_t ActivateICC(slot_t *slot, uint8_t atr[], uint8_t *atr_len)
{
    uint32_t ret;
    uint8_t mode;
    icc_t *icc = slot->icc;
	ICC_DefaultInit(icc);
    uint8_t work_mode = icc->work_mode;
    uint8_t voltage = icc->voltage;
	uint8_t FiDi = icc->FiDi;
	
    if(slot->icc == (icc_t *)0)
    {
        return ERR_CARD_ABSENT;
    }

    for(mode = COLD_RESET_MODE; ;)
    {
        *atr_len = 0;
        ICC_DefaultInit(icc);
//	        icc->work_mode = work_mode;
//	        icc->voltage = voltage;
//	        icc->FiDi = FiDi;
        Slot_Connect(slot);
        reset_icc(slot, mode);
        ret = receive_ATR(slot, atr, atr_len);

        if(ret != NO_ERR)
        {
        	LOGE("atr", "rx atr fail(%d)", ret);
            return ret;
        }
		LOG_SBUF("atr", atr, *atr_len);
        ret = decode_atr(slot, atr, *atr_len, mode);

        if(ret == NO_ERR)
        {
            if((work_mode == 0)
                    && (mode == COLD_RESET_MODE)
                    && config_voltage(atr, &voltage))
            {
                continue;
            }
        }

        if(ret != ERR_REJECT_ATR)
        {
            break;
        }

        if(mode == COLD_RESET_MODE)
        {
            mode = WARM_RESET_MODE;
        }
        else
        {
            break;
        }
    }

    return ret;
}

